/*
    File:       CalcController.m

    Contains:   xxx

    Written by: Andy Wildenberg

    Created:    Wed 09-Jul-1997

    Copyright:  (c)1997 by Apple Computer, Inc., all rights reserved.

    Change History (most recent first):
        7/5/00	KG	Updated for Project Builder on DP4
        9 July 97 -- first version of application
    
    You may incorporate this sample code into your applications without
    restriction, though the sample code has been provided "AS IS" and the
    responsibility for its operation is 100% yours.  However, what you are
    not permitted to do is to redistribute the source as "DSC Sample Code"
    after having made changes. If you're going to re-distribute the source,
    we require that you make it clear in the source that the code was
    descended from Apple Sample Code, but that you've made changes.
*/

#import "CalcController.h"

@implementation CalcController

- (void)clear:(id)sender
{
    [displayedNumber autorelease];
    displayedNumber = [[NSDecimalNumber zero] retain];
    [enteredNumber autorelease];
    enteredNumber = [[NSDecimalNumber zero] retain];
    [displayView setDoubleValue: 0];
    [self endEditingNumber];
    lastOperation = kNoOperator;
    usedDecimalPoint = NO;
}

- (void)equals:(id)sender
{
    if (enteringNumber)
      {
        [self endEditingNumber];
        [self performLastOperation];
        lastOperation = kNoOperator;
        [displayView setStringValue: [displayedNumber stringValue]];
      }
}

- (void)insertDigit:(id)sender
{
    NSString* oldValue;

    if (!enteringNumber)
      {
        [self beginEditingNumber];
      }


    oldValue = [displayView stringValue];
    [displayView setStringValue: [oldValue stringByAppendingString: [sender title]]];
}

- (void)beginEditingNumber
{
    enteringNumber = YES;
    usedDecimalPoint = NO;
    [displayView setStringValue: @""];
    [enteredNumber autorelease];
    enteredNumber = [displayedNumber copy]; 
}

- (void)endEditingNumber
{
    enteringNumber = NO;
    usedDecimalPoint = NO;

    [displayedNumber autorelease];
    displayedNumber = [NSDecimalNumber decimalNumberWithString: [displayView stringValue]];
    [displayedNumber retain];
}

- (void)decimalPoint:(id)sender
{
    NSString* oldValue;

    if (!usedDecimalPoint)
      {
        usedDecimalPoint = YES;
        if (!enteringNumber)
          {
            [self beginEditingNumber];
            [displayView setStringValue: @"0."];
          }
        else
          {
            oldValue = [displayView stringValue];
            [displayView setStringValue: [oldValue stringByAppendingString: @"."]];
          }
      }
}

-(void) awakeFromNib
{
    [self clear: self];
    [[displayView window] makeKeyAndOrderFront:nil];
}

- (void)operation:(id)sender
{
    if (enteringNumber)
      {
        [self endEditingNumber];
        [self performLastOperation];
        [displayView setStringValue: [displayedNumber stringValue]];
      }
    // no matter what, set the new operation in case the user changes his/her mind
    lastOperation = [sender tag];

}

- (void)performLastOperation
{
    if (lastOperation == kNoOperator)
      {
        return;
      }

    // it is possible to extensively rewrite the following code.  In all cases,
    // displayedNumber is autoreleased, assigned a new value and that new value is
    // retained.  Thus it would reduce the number of lines of code to put the
    // autorelease statement before the nest of if statements, and put the retain
    // statement after the nest of if statements.  However, I've duplicated the
    // statements just to brutally drive home the point that you need to autorelease
    // before you assign over your instance variables, and you need to retain them
    // after you've assigned to them.  Even in the case that none of the if statements
    // are executed, autoreleaseing and immediately retaining the same object is
    // perfectly acceptable.
    
    // This way of detecting NANs is a HACK!  Unfortunately, NaN is not ordered, so
    // if you ask any number if it's equal to NaN, it'll say yes.  So, instead we'll
    // ask if it's equal to an impossible combination of numbers -- zero and one.
    // The only 'number' equal to both is NaN
    if ((([displayedNumber compare: [NSDecimalNumber zero]] == NSOrderedSame) &&
         ([displayedNumber compare: [NSDecimalNumber one]] == NSOrderedSame)) ||
        (([enteredNumber compare: [NSDecimalNumber zero]] == NSOrderedSame) &&
         ([enteredNumber compare: [NSDecimalNumber one]] == NSOrderedSame)))
      {
        [displayedNumber autorelease];
        displayedNumber = [[NSDecimalNumber notANumber] retain];
        return;
      }
    else if (lastOperation == kAddOperator)
      {
        [displayedNumber autorelease];
       displayedNumber = [enteredNumber decimalNumberByAdding: displayedNumber];
        [displayedNumber retain];
      }
    else if (lastOperation == kSubtractOperator)
      {
        [displayedNumber autorelease];
        displayedNumber = [enteredNumber decimalNumberBySubtracting: displayedNumber];
        [displayedNumber retain];
      }
    else if (lastOperation == kMultiplyOperator)
      {
        [displayedNumber autorelease];
        displayedNumber = [enteredNumber decimalNumberByMultiplyingBy: displayedNumber];
        [displayedNumber retain];
      }
    else if (lastOperation == kDivideOperator)
      {
        if ([displayedNumber compare: [NSDecimalNumber zero]] != NSOrderedSame)
          {
            [displayedNumber autorelease];
            displayedNumber = [enteredNumber decimalNumberByDividingBy: displayedNumber];
            [displayedNumber retain];
          }
        else
          {
            [displayedNumber autorelease];
            displayedNumber = [[NSDecimalNumber notANumber] retain];
            [displayedNumber retain];
          }
      }
}

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
{
    return YES;
}

- (void)cut:(id)sender
{
    [self copy: self];
    [self clear: self];
}

- (void)copy:(id)sender
{
    NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
    [pasteboard declareTypes: [NSArray arrayWithObject: NSStringPboardType] owner: NULL];
    [pasteboard setString: [displayView stringValue] forType: NSStringPboardType];
}

- (void)paste:(id)sender
{
    NSPasteboard* pasteboard;
    NSString* pasteValue;

    if (!enteringNumber)
      {
        [self beginEditingNumber];
      }

    pasteboard = [NSPasteboard generalPasteboard];
    pasteValue = [pasteboard stringForType: NSStringPboardType];
    [displayView setStringValue: [[displayView stringValue] stringByAppendingString: pasteValue]];
}

// when self is released, it is necessary to release all of the variables we've retained
-(void)dealloc
{
    [displayedNumber release];
    [enteredNumber release];
}

@end
